1. Introduction to the OS

第一课 Computing System


如今,计算机系统无处不在,而操作系统在计算机系统中处于核心位置,简单地了解计算机系统为我们后面学习操作系统这个”房间中的大象“十分必要。

计算机系统是一个宏观的概念,计算机系统由硬件(hardware)软件(software) 共同构成,二者相辅相成。硬件提供了基础设施,软件则利用硬件为我们创造丰富多彩的应用体验。和操作系统的关系是什么?我们现在可以先下一个定义:操作系统是管理软硬件资源,为应用程序提供服务的程序。也就是说操作系统是一种管理软件和硬件的系统软件(resource manager)。

1.1 Computer Hardware

假如没有电,你所能看到的一大块铁壳子就是计算机的硬件。没有软件的加持,硬件对于我们很多人来说就是一块废铁。而没有硬件的支撑,软件又会犹如空中楼阁。换句话说,软件赋予了硬件更大的价值,而硬件又为软件提供了发挥价值的平台。

1.1.1 Components of Computer

在计算机组成的课程中,我们学到,计算机的五大部件:运算器、控制器、存储器、输入部件和输出部件。即要想组成一台图灵完备的计算机,我们至少需要:

  1. CPU:包括 ALU、CU 和一众寄存器,CU控制着包括 ALU 和其他部件进行各种操作。
  2. Memory:由成千上万个记忆单元组成,用来存储各种指令和数据。
  3. Inputs:输入部件,提供数据和命令供 CPU 运算。
  4. Outputs:输出部件,输出 CPU 处理后的结果。

抽象的概念是上层对下层复杂性的隐藏,整个计算机系统都是一层一层的抽象。CPU也是对数以亿计的门电路进行的抽象封装,CPU的引脚就是封装后的接口。尽管经过了封装,但裸机依然难用,因为我们总不可能将每个CPU的针脚都和一个开关/灯泡相连。咋办?

Pasted image 20240921032501.png

上图展示了一台计算机的主板,没有安装CPU和内存条。但我们从这些插槽能够窥见整个计算机是如何被组织起来的(bus did all the works)。科技的发展使得主板可以变得很小很漂亮,但假想一下,没有软件(包括操作系统),我们该怎么使用这台裸机?

1.1.2 Computer Workflow

当代计算机几乎都遵循以存储器为中心的冯诺依曼体系结构,将计算机分为五大部件——存储器、运算器、控制器、输入部件和输出部件。其中,控制器(CU)负责协调和控制其他四个部件完成各自的任务。因此,计算机的工作流程实际上是由控制器指挥其他部件按顺序执行指令。一个指令处理的完整流程包括输入、存储、计算和输出。

1.1.2.1 Input

计算机需要处理(计算)数据,五大部件中负责将外部信息输入到计算机系统中的是输入设备。常见的输入设备包括键盘、鼠标、扫描仪等。此外,现代计算机还包括触摸屏、语音识别系统和摄像头等高级输入设备,用于更加多样化和直观的用户交互。

1.1.2.2 Storage

在数据被处理前,输入的数据需要先被放到一个地方。这个地方就是我们一般说的主存储器/内存(Main Memory),所有需要被处理的数据都会事先被放到主存中。

除了主存外,系统中一般也需要包含辅助存储器(Storage)。主存储器速度快但容量小,主要用于临时数据的存储和快速访问。辅助存储器容量大但速度较慢,用于长期数据的存储。

1.1.2.3 Computation

当CPU要处理某些数据时,它会从cache或memory中读取并处理这些数据。在某些特定情况下,系统还会在硬盘中寻找相关的数据。

除了CPU,GPU(Graphics Processing Unit) 在一些高并行计算的应用场景中有其不可替代的优势。如图像处理、深度学习等。

1.1.2.4 Output

当数据处理完成之后,我们想得到处理后的结果。这时,系统就会让输出设备将计算机处理后的信息输出给用户。常见的输出设备包括显示器、打印机、扬声器等。

1.2 Computer Software

软件是运行在硬件上的一系列程序和数据的集合。软件告诉计算机硬件需要先这样,在那样...。我们前面说,硬件提供了计算机系统的基础设施。但仅靠硬件,我们使用计算机将会十分不便,因为和直接操作裸机差不多。

为了解决这个问题,人们发明了操作系统,它帮助我们管理计算机的硬件资源并为上层应用提供服务,也间接地管理了软件资源。有了OS,它会帮我们运行软件,我们只需要告诉操作系统要运行哪个程序就可以了。

1.2.1 Operating System Behind the Scene

计算机自发明之初就一直为人们的生活提供着便利,各式各样的计算机软件更是层出不穷。我们的生活中充斥着让人感到新奇和兴奋的应用软件,当我们想让计算机帮我们自己做事情时,我们就需要把自己的想法告诉计算机,这就要求我们编写一个软件让计算机运行。而这一切是如何完成的?

计算机系统是建立在一层层的抽象之上的。计算机很笨,无法理解人类抽象的思维,因此,我们需要将我们的想法用计算机能够理解的方式传达给它(我们下节课会介绍)。当程序编写好后,我们会将穿好孔的纸带交给穿孔纸带机(punch tape machine)让计算机读取这些孔的方式来存储数据或进行输出么?当然不了,现代的操作系统为我们提供了许多便利。

当应用程序编写好之后,我们只需要将编写好的程序交给操作系统,操作系统就会代为我们将二进制的机器指令交给硬件执行,执行完毕后为用户返回结果。操作系统提供了对硬件资源的抽象和管理,使用户不再需要直接与计算机硬件对接,替代了人工与裸机硬件的交互。操作系统通过驱动程序和系统调用接口,屏蔽了硬件的复杂性,使应用程序可以通过操作系统提供的标准化的接口访问硬件资源。简化了应用程序开发,也提高了系统的稳定性和安全性。

Pasted image 20241123001548.jpg

程序在机器上运行时不能直接使用硬件部件,主要有两方面的原因。一是失去了上层的抽象,应用程序很难去真正使用这些部件。还有就是为了系统的安全性,防止应用程序直接操作硬件导致系统崩溃或数据损坏。当应用程序真正想要访问系统资源时,应用程序就需要向操作系统提出相关的请求,让操作系统代为完成。这个”请求“我们称之为系统调用(system call),我们后续会逐步学习到。

第二课 From Machine Code to High Level Language


当我们想要创建自己的软件时,我们需要将想法告诉计算机。计算机是无法理解人类的语言的,计算机能够理解的只有特定架构下的01指令。我们说抽象是将原本细节化的东西进行封装,那么从高级语言到机器语言的过程其实就是一个逆抽象的过程(一条高级语言指令可能对应很多条机器语言指令)。毕竟计算机很笨嘛,只能按照特定的方式处理和执行指令。

2.1 Assembly to Machine Code

机器语言就是机器能够直接识别和执行的指令,机器语言和处理器的架构息息相关。对于不同的机器,使用的机器语言和汇编语言是不同的。这是由指令集架构ISA(Instruction Set Architecture) 所决定的(如x86、ARM、RISC-V、MIPS等)。见ISA, Instructions and CPU

尽管汇编和机器码一一对应,但这就是一次封装和抽象。相比于机器码,汇编的可读性要强很多。以下,我们展示两种采用不同思想的指令集(CISC 和 RISC)的x86架构和ARM架构下对内存中的数进行+2的加法操作。虽然很繁琐,但相比机器码总算是顺眼多了。

;CISC类型的x86架构:
; 假设edi寄存器包含了目标内存地址
add dword [edi], 2
;RISC类型的ARM架构: ARM架构的指令集通常不允许直接对内存执行算术运算
; 假设r0寄存器包含了目标内存地址
ldr r1, [r0]
add r1, r1, #2
str r1, [r0]

2.2 High Level Language to Assembly

高级语言是汇编的又一层封装和抽象。高级语言增加了代码在不同平台上的可移植性,屏蔽了底层细节,使得同一段代码可以在不同架构的机器下运行。高级语言通过编译器编译成特定平台的汇编语言,再由特定平台的汇编器将汇编代码转换成机器码供计算机读取。

Unix系统最初就是用汇编语言编写的,然而汇编语言是machine-specific的,不支持不同平台的移植。代码的可移植性一直是计算机科学夜以继日想要解决的问题。虽然第一个高级语言 FORTRAN 的出现代表着编程语言有了更高层次的抽象,但最开始仍未解决可移植性问题。即你可能需要在不同的平台上写不同的程序。

C语言的出现改变了这一局面。C语言设计的初衷之一就是为了实现代码的可移植性。它通过提供一个接近底层硬件的抽象层,使得程序员可以编写在不同硬件平台上运行的代码,而不需要对每个平台进行大量的修改。

2.3 AI Era: Human Logic to High Level Language?

如今,我们的生活中充斥着各种各样的LLMs,它们好似一个know-it-all,能够回答世间万物。可预见的未来,我们是否能看到AI帮我们编程呢?

第三课 Execution Cycle


指令执行周期,又称指令周期。通常由取指令指令解码执行结果写回 四部分组成。在指令周期中,通常要用到以下几个寄存器:PC寄存器、MAR寄存器、MDR寄存器、IR寄存器。(MDR寄存器 = MBR寄存器)

3.1 X+Y Cycle by Example

以X+Y加法指令为例,其指令执行周期如下:
Pasted image 20240405005008.png

3.1.1 Fetch Cycle

控制单元(CU)负责从内存中获取下一条要执行的指令。它通过程序计数器(PC)得到当前指令的地址,从内存中读取指令,将指令加载到指令寄存器(IR)中。完成这一操作后CU会更新PC中的值(进行PC + 1的操作),以指向下一条要执行指令的地址。

Fetch顺序:PC(In charge of CU)->MAR->(MEMORY)->MDR->IR->(Instruction executes)

3.1.2 Decode Cycle

在指令被加载到IR后,由控制单元解码指令,确定它是一条加法指令,并识别出操作数位于寄存器A和寄存器B。此阶段确定了需要执行的具体操作及涉及的数据。

3.1.3 Execute Cycle

根据CU的控制信号,ALU执行实际加法操作。它从寄存器s读取值,执行加法操作并将结果暂存。

3.1.4 Write-back Cycle

在加法操作完成后,CU指示将ALU的计算结果写回寄存器。(有的指令并不需要写回)

第四课 Abstraction, Interfaces and Virtualization


All problems in computer science can be solved by another level of indirection.

4.1 Abstraction/Virtualization

前两课我们就隐隐约约在强调抽象这个概念了,抽象是计算机科学大厦得以建立的根本。我们在第一课说CPU是门电路的抽象,主板通过针脚和CPU、内存相连又对这些硬件进行了抽象,操作系统通过HAL层对整个计算机硬件进行了抽象等等等等。通过不断的抽象化隐藏复杂性的同时只展示最关键的信息(也就是接口),使得更高层的应用人员可以忽略底层细节,专注于最重要的事情。

4.2 Interfaces

这里不给出接口的定义。我们需要明白的是:通过一步一步的抽象,我们能够看到更高维度的问题。抽象的意义就在于为上层裸露接口。便于我们更上一层的应用。接口可以是硬件与硬件之间的,比如主板上的各种端口,也可以是软件与软件之间的,比如程序之间用来交换数据的应用程序编程接口(Application Program Interface , API)。除此之外,还有硬件和软件之间的接口,即HAL。

顺便一提,ISA也可以看成一种接口。

4.3 Virtualized Machine

当你使用电脑时,你使用的其实并不是一台“真正的机器”,而是为你管理机器的操作系统。你所看到精美的画面、流畅的操作无一不是操作系统为你提供的。无论是CPU、内存还是显示器外设,我们都能将其视为“资源”。这些资源并不好使用,没关系,操作系统会帮我们将这些物理资源虚拟并转换成通用的虚拟资源,据此,我们也称操作系统为“虚拟的机器”。

面向应用程序,操作系统通过设备驱动程序硬件抽象层(HAL) 将硬件资源进行抽象,为应用程序提供API接口。使应用程序能够使用标准化的API调用(如system calls)来访问各种硬件资源(如CPU、内存、打印机、显示设备等),而不需要知道硬件的具体实现细节。

面向用户,软件操作系统提供了用户接口(如 图形用户界面GUI命令行界面CLI ),将复杂的系统操作抽象化成用户友好的命令和图形界面。用户可以通过点击图标、菜单和按钮或输入简单的命令来执行复杂的操作,无需了解背后的实现机制。

第五课 OS Makes Your Life Easier


5.1 Sharing

在本阶段的前面,我们不断地展示计算机和操作系统是如何进行一步步的抽象的。经过对下层的抽象虚拟化,操作系统能够为应用进程提供、分配并管理虚拟化后的硬件资源。在这种视角下,我们可以将操作系统称作资源管家(resource manager)。通过虚拟化物理内存,操作系统能使不同的应用进程共享同一块内存;甚至通过划分不同的时间片,我们还可以让不同的应用程序共享同一片CPU,这种特性就是并发

5.2 Concurrency

并发是操作系统为我们带来的另一个礼物。并发实现在操作系统对 CPU 虚拟化之上,在操作系统眼中,CPU 是可以分配给应用进程的资源。为了公平,操作系统可以让运行中的每个进程都轮流地使用 CPU(例如每个进程每次使用 1 毫秒)。这样即使只有一个 CPU,在用户眼中也好像很多进程(任务)在同时运行。这种特性使得一台主机服务多个用户变为现实。

多任务处理(multitasking)就是并发的一种实现方式,它允许多个任务(进程或线程)在同一时间段内交替执行。操作系统通过快速切换任务,使得每个任务都能在短时间内获得 CPU 的使用权,从而在用户看来,多个任务似乎在同时进行。

5.3 Asynchronous Operations

异步操作是指在执行某个操作时,不需要等待该操作完成,而是可以继续执行其他操作。当异步操作完成时,会通过某种方式通知执行者。异步机制在操作系统中非常重要,尤其是在处理I/O操作。

操作系统通过中断和信号机制来实现异步操作。当某个I/O操作完成时,硬件会发送一个中断信号给CPU,CPU会暂停当前的任务,转而处理这个中断信号。处理完中断信号后,CPU会恢复之前的任务。这样,进程就不需要一直等待I/O操作的完成,而是可以在I/O操作完成时被通知。

异步操作不仅限于I/O操作,还可以应用于其他需要等待的操作,比如网络通信、定时任务等。通过异步操作,操作系统能够更高效地利用资源,提高系统的响应速度和吞吐量。

5.4 Persistence

目前来看,主存中的主存都是易失性的,这种特性使得存储在主存中的程序和数据很容易由于掉电或死机的原因丢失掉。你半天的劳动成果就可能毁于一旦。而且每次都得重新手动将程序调入内存,更不用说早期的内存是非常金贵的。这些都将迫使我们寻找一个解决方案,将数据长久的储存起来。

虽然主存不是非易失性的,但是我们的确有些外设提供这种数据持久化存储的保障,比如早期的软盘驱动器(floppy disk drive, FDD),还有现在流行的固态存储(solid-state drive, SSD) 等。由于我们将文件放在这些非易失性存储器中,因而和这些非易失性存储介质进行交互的操作系统子系统我们称为文件系统(File system)

5.5 Security and Reliability

5.5.1 Security

5.5.2 Reliability

第六课 Operating System


Operating systems are those programs that interfaces the machine with the application programs. The main function of these systems is to dynamically allocate the shared resources to the executing programs. - What Can Be Automated

操作系统的四个特征是虚拟(virtualization)异步(asynchronous operations)并发(concurrency)共享(sharing)。虚拟是其他特征实现的基础,操作系统将底层硬件抽象成上层应用程序可以向操作系统申请的虚拟资源。不难理解操作系统通过资源的分配和回收就可以实现共享和并发。异步则与其他三者不同,异步机制使得CPU不需要和慢速I/O一直打交道,提高了CPU的运行效率。

通过上面的学习,我们应该能够明白操作系统的职责之所在。OS最基本的职责就是为我们提供一些抽象,让系统方便使用(user's view)。除此之外,操作系统还应该管理资源,让系统的性能得到最大的利用。操作系统还需要为应用程序提供保护,让进程彼此隔离防止恶意进程伤害系统上的其他进程(system's view)。